package com.example.demo.searcher;

import org.ansj.domain.Term;
import org.ansj.splitWord.analysis.ToAnalysis;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;

//通过这个类，完成整个搜索过程
public class DocSearCher {
    private static String STOP_WORD_PATH = null;

    static {
        if(Config.isOnline){
            STOP_WORD_PATH = "/root/install/doc_searcher_index/stop_word.txt";
        }else{
            STOP_WORD_PATH = "E:\\javaEE\\doc_searcher_index\\stop_word.txt";
        }
    }

    private HashSet<String> stopWords = new HashSet<>();
    //索引对象的实例
    private Index index = new Index();

    //完成索引加载的工作
    public DocSearCher(){
        index.load();
        loadStopWords();
    }

    public List<Result> search(String query){
        List<Term> oldTerms = ToAnalysis.parse(query).getTerms();

        List<Term> terms = new ArrayList<>();
        for (Term term : oldTerms){
            if(stopWords.contains(term.getName())){
                continue;
            }
            terms.add(term);
        }

        List<List<Weight>> termResult = new ArrayList<>();
        for (Term term : terms){
            String word = term.getName();
            List<Weight> invertedList = index.getInverted(word);
            if(invertedList == null){
                //这个词在所有文档中都没有出现
                continue;
            }
            termResult.add(invertedList);
        }

        List<Weight> allTermResult = mergeResult(termResult);

        allTermResult.sort(new Comparator<Weight>() {
            @Override
            public int compare(Weight o1, Weight o2) {
                //如果是升序排序：return o1.getWeight() - o2.getWeight();
                //如果是降序排序：return o2.getWeight() - o1.getWeight();
                return o2.getWeight() - o1.getWeight();
            }
        });

        List<Result> results = new ArrayList<>();
        for (Weight weight : allTermResult){
            DocInfo docInfo = index.getDocINfo(weight.getDocId());
            Result result = new Result();
            result.setTitle(docInfo.getTitle());
            result.setUrl(docInfo.getUrl());
            result.setDesc(GenDesc(docInfo.getContent(), terms));
            results.add(result);
        }
        return results;
    }

    static class Pos {
        public int row;
        public int col;

        public Pos(int row, int col) {
            this.row = row;
            this.col = col;
        }
    }

    private List<Weight> mergeResult(List<List<Weight>> sourse) {
        for (List<Weight> curRow : sourse){
            curRow.sort(new Comparator<Weight>() {
                @Override
                public int compare(Weight o1, Weight o2) {
                    return o1.getDocId() - o2.getDocId();
                }
            });
        }

        List<Weight> target = new ArrayList<>();

        PriorityQueue<Pos> queue = new PriorityQueue<>(new Comparator<Pos>() {
            @Override
            public int compare(Pos o1, Pos o2) {
                Weight w1 = sourse.get(o1.row).get(o1.col);
                Weight w2 = sourse.get(o2.row).get(o2.col);
                return w1.getDocId() - w2.getDocId();
            }
        });

        for (int row = 0; row < sourse.size(); row++){
            queue.offer(new Pos(row, 0));
        }

        while (!queue.isEmpty()){
            Pos minPos = queue.poll();
            Weight curWeight = sourse.get(minPos.row).get(minPos.col);
            if(target.size() > 0){
                Weight lastWeight = target.get(target.size() - 1);
                if(lastWeight.getDocId() == curWeight.getDocId()){
                    lastWeight.setWeight(lastWeight.getWeight() + curWeight.getWeight());
                }else {
                    target.add(curWeight);
                }
            } else {
                target.add(curWeight);
            }
            Pos newPos = new Pos(minPos.row, minPos.col + 1);
            if(newPos.col >= sourse.get(newPos.row).size()){
                continue;
            }
            queue.offer(newPos);
        }
        return target;
    }

    private String GenDesc(String content, List<Term> terms) {
        int firstPos = -1;
        for (Term term : terms){
            String word = term.getName();

            content = content.toLowerCase().replaceAll("\\b" + word + "\\b", " " + word + " ");
            firstPos = content.indexOf(" " + word + " ");
            if(firstPos >= 0){
                break;
            }
        }

        if(firstPos == -1){
            //所有的分词结果都不在正文中存在
            if(content.length() > 160){
                return content.substring(0, 160) + "...";
            }
            return content;
        }

        String desc = "";
        int descBeg = firstPos < 60 ? 0 : firstPos - 60;
        if(descBeg + 160 > content.length()){
            desc = content.substring(descBeg);
        } else {
            desc = content.substring(descBeg, descBeg + 160) + "...";
        }

        for (Term term : terms){
            String word = term.getName();
            //全字匹配
            desc = desc.replaceAll("(?i) " + word + " ", "<i> " + word + " </i>");
        }
        return desc;
    }

    public void loadStopWords(){
        try(BufferedReader bufferedReader = new BufferedReader(new FileReader(STOP_WORD_PATH))){
            while(true){
                String line = bufferedReader.readLine();
                if(line == null){
                    break;
                }
                stopWords.add(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        DocSearCher docSearCher = new DocSearCher();
        Scanner scanner = new Scanner(System.in);
        while (true){
            System.out.print("-> ");
            String query = scanner.next();
            List<Result> results = docSearCher.search(query);
            for (Result result : results){
                System.out.println("=============");
                System.out.println(result);
            }
        }
    }
}
